package baseFx.tests.database.mybatis;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@Intercepts({
//        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
//        @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PageInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        List<ParameterMapping> pm = ms.getBoundSql(args[1]).getParameterMappings();
        pm.addAll(pm);
        String sql = ms.getBoundSql(args[1]).getSql();
        sql = "select count(1) c from (" + sql + ")t;" + sql;
        SqlSource sqlSource = new StaticSqlSource(ms.getConfiguration(), sql, pm);
        MappedStatement pageMs = copyFromMappedStatement(ms, sqlSource);
        args[0] = pageMs;
        return invocation.proceed();
    }

    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        String msid = ms.getId() + "ByPage";
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), msid, newSqlSource, ms.getSqlCommandType());

        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        List<ResultMap> maps = new ArrayList<>();
        ResultMap.Builder rmBuilder = new ResultMap.Builder(ms.getConfiguration(), msid, Integer.class, new ArrayList<>());
        maps.add(rmBuilder.build());
        maps.addAll(ms.getResultMaps());
        builder.resultMaps(maps);
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());

        return builder.build();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
